package cn.tannn.surenessdemo.user.dao;

import cn.tannn.surenessdemo.user.entity.AuthResource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * @author tan
 * @date 2022-07-18 11:00:57
 */
public interface AuthResourceDao extends JpaRepository<AuthResource, Long> {

    /**
     * 刷新权限用的接口
     * 加载 需拦截的资源（即拦截资源) , eg: /api/v2/host===post===[role2,role3,role4]
     * @return resource-role
     */
    @Query(value = "SELECT  CONCAT(LOWER(res.uri),'===',LOWER(res.method),'===[',IFNULL(GROUP_CONCAT(DISTINCT role.code),''),']') " +
            "FROM auth_resource res " +
            "LEFT JOIN auth_role_resource_bind bind on res.code = bind.resource_code " +
            "LEFT JOIN (select trole.`code` from auth_role trole where `status` = 1)  role on role.code = bind.role_code " +
            "where res.status = 1 " +
            "group by res.code", nativeQuery = true)
    Optional<List<String>> getEnableResourcePathRoleData();



    /**
     * 刷新权限用的接口
     * 加载 不被拦截的资源（即放行资源)，例如/api/v2/host===post
     * @return resouce set
     */
    @Query("select CONCAT(LOWER(resource.uri),'===', resource.method) " +
            "from AuthResource resource where resource.status = 0 order by resource.code")
    Optional<List<String>> getDisableResourcePathData();

    /**
     * 以分页的形式获取当前角色拥有的可用API资源
     * @param roleCode roleCode
     * @param request page
     * @return api resource list
     */
    @Query("select distinct resource from AuthResource resource " +
            "left join AuthRoleResourceBind bind on bind.resourceCode = resource.code " +
            "where bind.roleCode = :roleCode " +
            "order by resource.code asc")
    Page<AuthResource>  findRoleOwnResource(@Param("roleCode") String roleCode, Pageable request);


    /**
     * 获取当前角色拥有的可用API资源
     * @param roleCode roleCode
     * @return api resource list
     */
    @Query("select distinct resource from AuthResource resource " +
            "left join AuthRoleResourceBind bind on bind.resourceCode = resource.code " +
            "where bind.roleCode = :roleCode " +
            "order by resource.code asc")
    List<AuthResource>  findRoleOwnResource(@Param("roleCode") String roleCode);

    /**
     * 以分页的形式获取当前角色拥有的可用API资源
     * @param roleCode roleCode
     * @param request page
     * @return api resource list
     */
    @Query("select distinct resource from AuthResource resource " +
            " where resource.code not in " +
            "(select distinct bind.resourceCode from AuthRoleResourceBind bind where bind.roleCode = :roleCode) " +
            "order by resource.id asc ")
    Page<AuthResource> findRoleNotOwnResource(@Param("roleCode") String roleCode, Pageable request);

    /**
     * 获取当前角色拥有的可用API资源
     * @param roleCode roleCode
     * @return api resource list
     */
    @Query("select distinct resource from AuthResource resource " +
            " where resource.code not in " +
            "(select distinct bind.resourceCode from AuthRoleResourceBind bind where bind.roleCode = :roleCode) " +
            "order by resource.id asc ")
    List<AuthResource> findRoleNotOwnResource(@Param("roleCode") String roleCode);


    /**
     * 根据code判断AuthResource是否存在
     * @param code AuthResource code
     * @return boolean
     */
    boolean existsByCode(String code);

    /**
     * 查询
     * @param code code
     * @return AuthResource
     */
    AuthResource findByCode(String  code);

    /**
     * 根据code 删除
     * @param resourceCode AuthResource code
     */
    @Transactional(rollbackFor = Exception.class)
    @Modifying
    void deleteByCode(String resourceCode);


    /**
     * 更新状态
     * @param codes codes
     * @param status status  1:拦截、0：不拦截（此资源不生效不做权限控制）
     */
    @Modifying
    @Transactional(rollbackFor = Exception.class)
    @Query("update AuthResource ar set ar.status = :status where  ar.code in (:codes) ")
    void changeStatus(@Param("codes") List<String> codes ,@Param("status") Integer status);


    /**
     *  拦截所有资源
     */
    @Modifying
    @Transactional(rollbackFor = Exception.class)
    @Query("update AuthResource ar set ar.status = 1 ")
    void enableAll();

}
